#include "lex_ana.h"

#include <string>

using namespace std;

int Lexical_Analysis::getWordType(char word)
{
    if (word == ' ' || word == '\n' || word == '\r')
        return WORD_SPACE;
    if (word == '.')
        return WORD_DOT;
    if (word == '"')
        return WORD_QUOTE;
    if (word == '{' || word == '}' || word == '[' || word == ']' || word == ':' || word == ',')
        return WORD_SYMBOL;
    if (word == '-')
        return WORD_MINUS;
    if (word == '\\')
        return WORD_BACK_SLASH;

    if (word == 'T' || word == 't')
        return WORD_T;
    if (word == 'R' || word == 'r')
        return WORD_R;
    if (word == 'U' || word == 'u')
        return WORD_U;
    if (word == 'E' || word == 'e')
        return WORD_E;
    if (word == 'F' || word == 'f')
        return WORD_F;
    if (word == 'A' || word == 'a')
        return WORD_A;
    if (word == 'L' || word == 'l')
        return WORD_L;
    if (word == 'S' || word == 's')
        return WORD_S;
    if (word == 'N' || word == 'n')
        return WORD_N;

    return WORD_CHAR;
}

void Lexical_Analysis::init_DFA()
{
    DFA_Table[STAT_IDLE][WORD_CHAR] = STAT_STRING;
    DFA_Table[STAT_IDLE][WORD_SYMBOL] = STAT_SYMBOL;
    DFA_Table[STAT_IDLE][WORD_DOT] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_QUOTE] = STAT_STR_QUOTE;
    DFA_Table[STAT_IDLE][WORD_SPACE] = STAT_IDLE;
    DFA_Table[STAT_IDLE][WORD_MINUS] = STAT_STRING;
    DFA_Table[STAT_IDLE][WORD_T] = STAT_STRING;
    DFA_Table[STAT_IDLE][WORD_R] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_U] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_E] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_F] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_A] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_L] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_S] = STAT_ERROR;
    DFA_Table[STAT_IDLE][WORD_N] = STAT_STRING;
    DFA_Table[STAT_IDLE][WORD_BACK_SLASH] = STAT_ERROR;

    DFA_Table[STAT_STRING][WORD_CHAR] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_SYMBOL] = STAT_SYMBOL;
    DFA_Table[STAT_STRING][WORD_DOT] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_QUOTE] = STAT_ERROR;
    DFA_Table[STAT_STRING][WORD_SPACE] = STAT_IDLE;
    DFA_Table[STAT_STRING][WORD_MINUS] = STAT_ERROR;
    DFA_Table[STAT_STRING][WORD_T] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_R] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_U] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_E] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_F] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_A] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_L] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_S] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_N] = STAT_STRING;
    DFA_Table[STAT_STRING][WORD_BACK_SLASH] = STAT_ERROR;

    DFA_Table[STAT_STR_QUOTE][WORD_CHAR] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_SYMBOL] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_DOT] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_QUOTE] = STAT_IDLE; // 退出字符串
    DFA_Table[STAT_STR_QUOTE][WORD_SPACE] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_MINUS] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_T] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_R] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_U] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_E] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_F] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_A] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_L] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_S] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_N] = STAT_STR_QUOTE;
    DFA_Table[STAT_STR_QUOTE][WORD_BACK_SLASH] = STAT_STR_QUOTE;

    DFA_Table[STAT_SYMBOL][WORD_CHAR] = STAT_STRING;
    DFA_Table[STAT_SYMBOL][WORD_SYMBOL] = STAT_SYMBOL;
    DFA_Table[STAT_SYMBOL][WORD_DOT] = STAT_ERROR;
    DFA_Table[STAT_SYMBOL][WORD_QUOTE] = STAT_STR_QUOTE;
    DFA_Table[STAT_SYMBOL][WORD_SPACE] = STAT_IDLE;
    DFA_Table[STAT_SYMBOL][WORD_MINUS] = STAT_STRING;
    DFA_Table[STAT_SYMBOL][WORD_T] = STAT_STRING;
    DFA_Table[STAT_SYMBOL][WORD_R] = STAT_ERROR;
    DFA_Table[STAT_SYMBOL][WORD_U] = STAT_ERROR;
    DFA_Table[STAT_SYMBOL][WORD_E] = STAT_ERROR;
    DFA_Table[STAT_SYMBOL][WORD_F] = STAT_STRING;
    DFA_Table[STAT_SYMBOL][WORD_A] = STAT_ERROR;
    DFA_Table[STAT_SYMBOL][WORD_L] = STAT_ERROR;
    DFA_Table[STAT_SYMBOL][WORD_S] = STAT_ERROR;
    DFA_Table[STAT_SYMBOL][WORD_N] = STAT_STRING;
    DFA_Table[STAT_SYMBOL][WORD_BACK_SLASH] = STAT_ERROR;
}

vector<string> Lexical_Analysis::analysis(const string &s)
{
    vector<string> tokens;
    char ch;
    int pre_idx = 0;
    int now_stat = STAT_IDLE;

    for (int i = 0; i < s.size(); i++)
    {
        ch = s[i];
        int wtype = getWordType(ch);
        int next_stat = DFA_Table[now_stat][wtype];

        // printf("%d + %d %c = %d \n", now_stat, wtype, ch, next_stat);

        // 如果前后状态发生改变
        if (now_stat != next_stat)
        {
            if (next_stat == STAT_ERROR)
            {
                printf("error: char=%c , now_stat=%d, next_stat=%d \n", ch, now_stat, next_stat);
                break;
            }
            if (now_stat == STAT_SYMBOL)
            {
                // cout << "SYMBOL:" << pre_idx << ", " << i << endl;
                tokens.push_back(s.substr(pre_idx, (i - pre_idx)));
                pre_idx = i;
            }
            if (now_stat == STAT_STR_QUOTE)
            {
                // cout << "STAT_STR_QUOTE:" << pre_idx << ", " << i << endl;
                tokens.push_back(s.substr(pre_idx, (i - pre_idx + 1)));
                pre_idx = i;
            }
            if (now_stat == STAT_STRING)
            {
                // cout << "STAT_STRING:" << pre_idx << ", " << i << endl;
                tokens.push_back(s.substr(pre_idx, (i - pre_idx)));
                pre_idx = i;
            }
            if (now_stat == STAT_IDLE)
            {
                // cout << "STAT_IDLE:" << pre_idx << ", " << i << endl;
                pre_idx = i;
            }
        }
        // 如果前后都是 符号
        else if (now_stat == STAT_SYMBOL)
        {
            tokens.push_back(s.substr(pre_idx, (i - pre_idx)));
            pre_idx = i;
        }
        now_stat = next_stat;
    }

    return tokens;
}